package domain;


import domain.Node;
import domain.enums.GameStatus;
import domain.enums.PlayerType;

public class Minimax 
{
	private Node theTree;
	private int maxDepth;
	private boolean isBlack;
	
	private final int INFINITY = 10000;
	
//	public Minimax(Node theTree, int maxDepth)
//	{
//		
//		this.theTree = theTree;
//		this.maxDepth = maxDepth;
//	}
	
	public Minimax(boolean isBlack, Board board, int maxDepth)
	{
		theTree = new Node(board, null, null);
		this.isBlack = isBlack;
		this.maxDepth = maxDepth;
	}
	
	public Move getNextMove()
	{
		getMax(theTree, maxDepth, isBlack);
		
		// find the child of theTree whose value matches that of theTree
		Node nextNode = null;
		for (Node child : theTree.getChildren())
		{
			if (theTree.hasEqualValue(child))
			{
				if (nextNode != null)
				{
					if (nextNode.getDepthFromHere() > child.getDepthFromHere())
						nextNode = child;
				}
				else
					nextNode = child;
			}
		}
		
		// nextNode should not be null
		return nextNode.getLastMove();
	}
	
	private int getMax(Node node, int depth, boolean isBlack)
	{
		if (depth <= 0 || !(node.getBoard().getGameStatus().equals(GameStatus.NO_WINNER)))
		{
			node.setValue(heuristic(node));
			return node.getValue();
		}
		node.setValue(-INFINITY*2);
		
		boolean depthIncreased = false;
		
		//all child nodes are added by get all the available moves
		
		if(isBlack)
		{
		//	ArrayList<Player> black = node.getBoard().blackPlayers;
			for(Position p: node.getBoard().getAvailableMoves())
			{
				Board newB = new Board(node.getBoard());
				newB.blackPlayers.add(new Player(p, PlayerType.BLACK));
				Move move = new Move(isBlack, p);
				node.addChild(new Node(newB, node, move));
			}
		}
		else
		{
		//	ArrayList<Player> white = node.getBoard().whitePlayers;
			
			for(Position p: node.getBoard().getAvailableMoves())
			{
				Board newB = new Board(node.getBoard());
				newB.whitePlayers.add(new Player(p, PlayerType.WHITE));
				Move move = new Move(isBlack, p);
				node.addChild(new Node(newB, node, move));
			}
		
		}
		
		for (Node child : node.getChildren())
		{
			if (!depthIncreased)
			{
				depthIncreased = true;
				node.increaseDepth();
			}
			node.setValue(Math.max(node.getValue(), getMin(child, depth - 1, !isBlack)));
		}
		return node.getValue();
	}
	
	
	private int getMin(Node node, int depth, boolean isBlack)
	{
		if (depth <= 0 || !node.getBoard().getGameStatus().equals(GameStatus.NO_WINNER))
		{
			node.setValue(heuristic(node));
			return node.getValue();
		}
		node.setValue(INFINITY*2);
		
		boolean depthIncreased = false;
		
		if(isBlack)
		{
			for(Position p : node.getBoard().getAvailableMoves())
			{
				Board newB = new Board(node.getBoard());
				newB.blackPlayers.add(new Player(p, PlayerType.BLACK));
				Move move = new Move(isBlack, p);
				node.addChild(new Node(newB, node, move));
			}
		}
		else
		{
			for(Position p : node.getBoard().getAvailableMoves())
			{
				Board newB = new Board(node.getBoard());
				newB.whitePlayers.add(new Player(p, PlayerType.WHITE));
				Move move = new Move(isBlack, p);
				node.addChild(new Node(newB, node, move));
			}
		}
		
		for (Node child : node.getChildren())
		{
			if (!depthIncreased)
			{
				depthIncreased = true;
				node.increaseDepth();
			}
			node.setValue(Math.min(node.getValue(), getMax(child, depth - 1, !isBlack)));
		}
		return node.getValue();
	}
	
	private int heuristic(Node node)
	{
		return node.getValue();
	}
}
